#!/usr/bin/env python
#encoding=utf-8

'''
git repository help class
'''

from git import *
from patch import mypatch
from util import ssh_cmd
from base import base
import util
import git
import os
import string

class myrepo(base):
	def __init__(self, name, repo_dir, git_url):
		super(myrepo, self).__init__()
		self._repo_dir = repo_dir
		self._git_url = git_url
		self._patch_list = []
		self._name = name
		self._pushed = False
		self._branch = None
		self._status = ''
		self._valid = True
		self._need_push = False
		self._applied_patch_num = 0

	@property
	def applied_patch_num(self):
		return self._applied_patch_num

	@property
	def status(self):
		return self._status

	@status.setter
	def status(self, new_value):
		self._status = new_value

	@property
	def is_pushed(self):
		return self._pushed
	
	@property
	def name(self):
		return self._name

	@property
	def patch_list(self):
		return self._patch_list

        @property
        def valid(self):
                return self._valid

	@property
	def change_log(self):
		if not self._valid or not self._need_push:
			return ""
		g = self._repo.git
		self._new_commit = getattr(self._repo.heads, self._branch)
		log_opt = "--oneline"
		log_cmd = "%s..%s" % (str(self._old_commit), str(self._new_commit))
		self._change_log = g.log(log_opt,log_cmd)
		return self._change_log

	def update_test_repo(self):
		cmds_template = [
                        'rm -rf /opt/git/frobisher/test_repo/{name}-test.git',
                        'cp -pR /opt/git/frobisher/{name}.git '
                        '/opt/git/frobisher/test_repo/{name}-test.git',
                        'sed -i \'/^\[hooks/,\$d\' /opt/git/frobisher/test_repo/'
                        '{name}-test.git/config'
                        ]

		if self._name == 'kernel':
			cmd = ' && '.join(c.format(name='linux-3.10.23') for c in cmds_template)
		else:
			cmd = ' && '.join(c.format(name=self._name) for c in cmds_template)

		ssh_cmds = 'ssh -t  %s@%s \"%s\"' % (self._conf.get_build('ltcphx_user'), \
                                                     self._conf.get_build('ltcphx_host'), \
                                                    cmd)

		self.logger.debug("ssh cmd - [%s]", ssh_cmds)
		(rc, out, err) = util.exec_command(ssh_cmds)
		self.logger.debug('ssh rc is [%d] out is [%s]' % (rc, out))
		return rc

	def initrepo(self):
		'''
			we need to call initrepo explicitly
		'''
		if not self.update_test_repo() == 0:
			# todo , need to handle it when self._repo is none.
			self.logger.debug('Update remote repo [%s] error' % self._repo_dir)
			self._valid = False
		try:
			self.logger.debug('Clone repo to [%s]...' % self._repo_dir)
			Repo.clone_from(self._git_url, self._repo_dir)
			self._repo = Repo(self._repo_dir)
		# to do
		except:
			self.logger.error("Init repository failed [%s]-[%s]" %\
                                        (self._name, self._git_url))
			self.logger.info("Try to update local repo")
			self._repo = Repo.init(self._repo_dir)
			self._repo.git.pull()
			#self._valid = False

	# add patch to repo
	def add_patch(self, patch):
		# add new patch to this repo
		# need to track all patch even repo is invalid
		if patch.valid:
			self._patch_list.append(patch)
			self.logger.debug("append patch: %s" % patch._message_subject)
			# set to patch's branch
			# if we got a patch series are not on same branch, set repo invalid
			if self._branch == None:
				self._branch = patch.branch
			if self._branch != patch.branch:
				self._valid = False
			self.logger.debug("Append patch: [%s] to branch [%s]" \
					% (patch._message_subject, self._branch))

	# check out to _branch
	def checkout(self):

		if not self._valid:
			return
		try:
			g = self._repo.git
			g.checkout(self._branch)
			# save old commit
			self._old_commit = getattr(self._repo.heads, self._branch).commit
		except git.exc.CheckoutError:
			# no branch
			self._status = "no branch : %s" % self._branch
			self._valid = False
		if not cmp(self._repo.head.reference, self._branch):
			self._valid = False

	def am_patch(self):
		if not self._valid:
			return
		r = True
		for patch in self._patch_list:
			if False == self.am(patch.path):
				patch.comment = "Apply patch failed"
				r = False
			else:
				patch.applied = True
				# we need to push if there is patch amed.
				self._need_push = True
				self._applied_patch_num += 1
		return r

	def am(self, patch_file):
		g = self._repo.git
		try:
			g.am(patch_file)
		except git.exc.GitCommandError:
			# todo g.am('abort') --abort
			# g.am('--abort')
			return False
		else:
			return True
	
	# if applied all patches,
	# push changes to git repo
	def push(self):
		if not self._need_push:
			self.logger.debug("[%s] no need to push" % self._name)
			return False
		# need to check if clean git repo first
		if not self._repo.is_dirty():
			try:
				g = self._repo.git
				g.push()
			except:
				self._valid = False
				self._status = 'Push error'
				return False
			else:
				self._pushed = True
				return True
		else:
			self.logger.error("[%s] repo is dirty" % self._name)
			self._valid = False
			self._status = 'Push error'
			return False
		
	def debug(self):
		print("reponame = [%s]" % self._name)
		print("git url = [%s]" % self._git_url)
		print("branch = [%s]" % self._branch)
		print("pushed = [%s]" % self._pushed)
		for patch in self._patch_list:
			patch.debug()
		
if __name__ == "__main__":
	r = myrepo('qemu', '/tmp/GIT/qemu', 'git://')
	r.update_test_repo()

